package com.alibaba.citrus.cr.mn.order.center.facade.function.common;

import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderLineWriteRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderQueryServiceRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderWriteRepository;
import com.alibaba.citrus.cr.common.enums.GeneralStatusEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.*;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.util.ThreadPoolUtil;
import com.alibaba.citrus.cr.mn.order.center.common.SetOrderTag;
import com.alibaba.citrus.cr.mn.order.center.common.util.AssertUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.DictionaryVerifyAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.FulfillmentOrderAbilityAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.SearchFulfullmentOrderRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.FulfillmentDetailGetResDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.FulfillmentGetResDTO;
import com.alibaba.cloud.retail.delivery.api.model.delivery.enums.FulfillmentDetailStatusEnum;
import com.alibaba.cloud.retail.delivery.api.model.delivery.enums.FulfillmentDirectionTypeEnum;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.contants.BcOrderConstants;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOrderBizIdsRequest;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.crb2btradecenter.sdo.OrderLineSDO;
import com.epoch.app.crb2btradecenter.sdo.OrderSDO;
import com.epoch.app.mnordercenter.model.dto.CommonAsyncMessageResponse;
import com.epoch.app.mnordercenter.model.dto.OrderAtomBatchCloseRequest;
import com.epoch.app.mnordercenter.model.dto.PushOrderInfoToMnSideRequestOrderInfo;
import com.epoch.app.mnordercenter.model.dto.SalesOrderRefuseRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomCloseRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomCloseResponse;
import com.epoch.app.mnordercenter.salesorderatom.dto.SapRefuseCallbackRequest;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * Chen.mu
 * 2023/5/11
 **/
public abstract class AbstractOrderAtomCloseService implements OrderAtomCloseService {
    private static final Log log = Log.getLogger(AbstractOrderAtomCloseService.class);

    @Autowired
    private EpochMessageService messageService;
    @Resource
    private OrderQueryServiceRepository orderQueryServiceRepository;
    @Resource
    private OrderWriteRepository orderWriteRepository;
    @Resource
    private OrderLineWriteRepository orderLineWriteRepository;
    @Resource
    private SendMsgService sendMsgService;
    @Resource
    private DictionaryVerifyAdapter dictionaryVerifyAdapter;
    @Resource
    private FulfillmentOrderAbilityAdapter fulfillmentOrderAbilityAdapter;

    public static final String EXCHANGE = "exchange";
    public static final String RETURN = "return";
    public static final String NORMAL = "normal";

    /**
     * 履约单所有状态
     */
    private static final Map<String, String> fulfillmentOrderStatusMap = Maps.newHashMap();

    /**
     * 逆向履约单状态
     */
    private static final Map<String, String> fulfillmentReverseOrderStatusMap = Maps.newHashMap();

    /**
     * 销售订单履约方式
     */
    private static final Map<String, String> fulfillmentTypeMap = Maps.newHashMap();

    /**
     * 退货订单履约方式
     */
    private static final Map<String, String> returnFulfillmentTypeMap = Maps.newHashMap();

    static {
        fulfillmentOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.WAIT_SUBMIT.getValue()), FulfillmentDetailStatusEnum.WAIT_SUBMIT.name());
        fulfillmentOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.SUBMIT.getValue()), FulfillmentDetailStatusEnum.SUBMIT.name());
        fulfillmentOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.WAIT_SEND.getValue()), FulfillmentDetailStatusEnum.WAIT_SEND.name());
        fulfillmentOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.PART_SEND.getValue()), FulfillmentDetailStatusEnum.PART_SEND.name());

        fulfillmentReverseOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.WAIT_SUBMIT.getValue()), FulfillmentDetailStatusEnum.WAIT_SUBMIT.name());
        fulfillmentReverseOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.SUBMIT.getValue()), FulfillmentDetailStatusEnum.SUBMIT.name());
        fulfillmentReverseOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.WAIT_RECEIVE.getValue()), FulfillmentDetailStatusEnum.WAIT_RECEIVE.name());
        fulfillmentReverseOrderStatusMap.put(String.valueOf(FulfillmentDetailStatusEnum.PART_RECEIVE.getValue()), FulfillmentDetailStatusEnum.PART_RECEIVE.name());

        fulfillmentTypeMap.put(FulfillmentTypeEnum.EXTERNAL_TO_EXTERNAL.getCode(), FulfillmentTypeEnum.EXTERNAL_TO_EXTERNAL.name());
        fulfillmentTypeMap.put(FulfillmentTypeEnum.EXTERNAL_TO_CENTRAL.getCode(), FulfillmentTypeEnum.EXTERNAL_TO_CENTRAL.name());

        returnFulfillmentTypeMap.put(FulfillmentTypeEnum.EXTERNAL_TO_EXTERNAL.getCode(), FulfillmentTypeEnum.EXTERNAL_TO_EXTERNAL.name());
        returnFulfillmentTypeMap.put(FulfillmentTypeEnum.CENTRAL_TO_EXTERNAL.getCode(), FulfillmentTypeEnum.CENTRAL_TO_EXTERNAL.name());
    }

    /**
     * 返回 销售 退货 换货Tag
     */
    protected abstract String getOrderTag();

    @Override
    public List<OrderAtomCloseResponse> batchClose(OrderAtomBatchCloseRequest request) {
        // 入参校验
        paramsCheck(request, OrderCategoryEnum.COMPANY.getCode());

        List<OrderAtomCloseRequest> orderList = Lists.newArrayList(request.getOrderList());

        // 构造返回结果
        List<OrderAtomCloseResponse> closeResponses = Collections.synchronizedList(new ArrayList<>());
        List<OrderSDO> orderSDOS = querySalesOrder(request);
        // 根据订单单号缓存订单
        Map<String, OrderSDO> orderMap = new HashMap<>();
        orderSDOS.forEach(o -> orderMap.put(o.getOrderBizId(), o));
        // 根据订单单号+订单行号缓存订单行
        Map<String, Map<String, OrderLineSDO>> orderLineMap = new ConcurrentHashMap<>();
        Iterator<OrderAtomCloseRequest> iterator = orderList.iterator();
        while (iterator.hasNext()) {
            OrderAtomCloseRequest orderAtomCloseRequest = iterator.next();
            OrderAtomCloseResponse closeResponse = new OrderAtomCloseResponse();
            closeResponse.setSalesOrderNo(orderAtomCloseRequest.getSalesOrderNo());
            closeResponse.setLineNum(orderAtomCloseRequest.getLineNum());
            closeResponse.setSuccess(Boolean.FALSE);
            OrderSDO order = orderMap.get(orderAtomCloseRequest.getSalesOrderNo());
            log.info("AbstractOrderAtomCloseService#batchClose order={}", JSON.toJSONString(order));
            if (!orderLineMap.containsKey(orderAtomCloseRequest.getSalesOrderNo())) {
                // 缓存订单行
                Map<String, OrderLineSDO> tempMap = new HashMap<>();
                for (OrderLineSDO orderLine : order.getOrderLineSDOS()) {
                    tempMap.put(orderLine.getSerialNumber(), orderLine);
                }
                orderLineMap.put(orderAtomCloseRequest.getSalesOrderNo(), tempMap);
            }

            // 根据订单行号取出订单行数据
            OrderLineSDO orderLine = orderLineMap.get(orderAtomCloseRequest.getSalesOrderNo()).get(orderAtomCloseRequest.getLineNum());
            // 校验订单行
            String message = this.checkOrderLine(orderLine, closeResponse);
            if (StringUtils.isNotBlank(message)) {
                // 校验不通过，组装错误信息
                closeResponses.add(closeResponse);
                iterator.remove();
                continue;
            }

            // 校验订单
            message = this.checkOrder(order, orderAtomCloseRequest.getSalesOrderNo(), closeResponse);
            if (StringUtils.isNotBlank(message)) {
                // 校验不通过，组装错误信息
                closeResponses.add(closeResponse);
                iterator.remove();
                continue;
            }
        }
        if (CollectionUtils.isEmpty(orderList)) {
            return closeResponses;
        }

        // 保存要调用sap拒绝接口的数据
        List<OrderAtomCloseRequest> sapCloseRequests = Collections.synchronizedList(new ArrayList<>());
        // 校验订单、补充外部单号和外部行号
        StopWatchUtils.start("销售订单批量关闭", "cancelRequestCheck");
        CountDownLatch countDownLatch = new CountDownLatch(orderList.size());
        orderList.forEach(orderAtomCloseRequest -> ThreadPoolUtil.execute(() -> {
            try {
                // 构造返回结果
                OrderAtomCloseResponse closeResponse = new OrderAtomCloseResponse();
                closeResponse.setSalesOrderNo(orderAtomCloseRequest.getSalesOrderNo());
                closeResponse.setLineNum(orderAtomCloseRequest.getLineNum());
                closeResponse.setSuccess(Boolean.FALSE);
                closeResponses.add(closeResponse);

                OrderSDO order = orderMap.get(orderAtomCloseRequest.getSalesOrderNo());
                // 根据订单行号取出订单行数据
                OrderLineSDO orderLine = orderLineMap.get(orderAtomCloseRequest.getSalesOrderNo()).get(orderAtomCloseRequest.getLineNum());
                // 设置外部单号和行号，调用sap拒绝接口时使用
                orderAtomCloseRequest.setOutOrderNo(order.getOuterOrderId());
                orderAtomCloseRequest.setOutLineNum(orderLine.getOuterOrderLineId());
                sapCloseRequests.add(orderAtomCloseRequest);

                // 提前保存订单修改人信息，sap回调后拿不到修改人信息
                order.setModifierId(orderAtomCloseRequest.getModifierCode());
                order.setModifierCode(orderAtomCloseRequest.getModifierCode());
                order.setModifierName2(orderAtomCloseRequest.getModifierName());
                order.setGmtModified(new Date());
                orderWriteRepository.updateOrder(order);

                // 提前保存订单行修改人信息，sap回调后拿不到修改人信息
                orderLine.setModifierId(order.getModifierId());
                orderLine.setModifierName(order.getModifierName());
                orderLine.setGmtModified(new Date());
                orderLineWriteRepository.modifyModifier(orderLine);

                // 修改更改后，重新设置状态
                closeResponse.setSuccess(Boolean.TRUE);
            } catch (Exception e) {
                log.error("AbstractOrderAtomCloseService#batchClose updateOrder error", e);
            } finally {
                countDownLatch.countDown();
            }
        }));

        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("AbstractOrderAtomCloseService#batchClose await error", e);
        }
        StopWatchUtils.stop();

        log.info("AbstractOrderAtomCloseService#batchClose sapCloseRequests={}", JSON.toJSONString(sapCloseRequests));
        // 发送消息触发调用sap拒绝接口
        StopWatchUtils.start("销售订单批量关闭", "sendMessage");
        if (CollectionUtils.isNotEmpty(sapCloseRequests)) {
            Map<String, String> map = new HashMap<>();
            map.put("_CZ_KEY", BcOrderConstants.TENANT_ID());
            messageService.sendMessage("sale_order_message", "CR_SALEORDER_V2", "SalesOrderRefuse",
                    UUID.randomUUID().toString(), JSON.toJSONString(sapCloseRequests), map);
        }
        StopWatchUtils.stop();
        return closeResponses;
    }

    /**
     * 校验履约单
     */
    protected boolean checkFulfillmentOrder(OrderSDO orderSDO, OrderLineSDO orderLineSDO,
                                            List<FulfillmentDetailGetResDTO> fulfillmentDetailDTOList,
                                            List<OrderAtomCloseResponse> closeResponses) {

        // 分公司订单不校验履约单
//        if (OrderCategoryEnum.COMPANY.getCode().equals(orderSDO.getOrderCategoryCode())) {
//            return true;
//        }

        if(SetOrderTag.NORMAL.equals(getOrderTag())) {
            // 销售订单履约类型（外仓发外仓收、外仓发大仓收）场景不允许关闭【整单维度】
            if (fulfillmentTypeMap.containsKey(orderSDO.getFulfillmentTypeCode())) {
                OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
                orderAtomCloseResponse.setSuccess(false);
                orderAtomCloseResponse.setSalesOrderNo(orderSDO.getOrderBizId());
                orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-003");
                orderAtomCloseResponse.setMessage("履约方式不支持关闭");
                closeResponses.add(orderAtomCloseResponse);
                return false;
            }
        } else if(SetOrderTag.RETURN.equals(getOrderTag())){
            if(returnFulfillmentTypeMap.containsKey(orderSDO.getFulfillmentTypeCode())){
                OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
                orderAtomCloseResponse.setSuccess(false);
                orderAtomCloseResponse.setSalesOrderNo(orderSDO.getOrderBizId());
                orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-003");
                orderAtomCloseResponse.setMessage("履约方式不支持关闭");
                closeResponses.add(orderAtomCloseResponse);
                return false;
            }
        }

        // 一盘货下的F-B订单不校验履约单
        if (OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode()) && SalesOrderTypeEnum.GROUP_STD_ORDER.getCode().equals(orderSDO.getOrderType())) {
            return true;
        }

        // 没有查到履约单，就不做校验
        if(CollectionUtils.isEmpty(fulfillmentDetailDTOList)){
            return true;
        }

        Map<String, List<FulfillmentDetailGetResDTO>> fulfillmentOrderDetailMap = fulfillmentDetailDTOList.stream().collect(Collectors.groupingBy(orderDetail ->
                orderDetail.getFromSys() + orderDetail.getBusinessType() + orderDetail.getBusinessUnitCode() + orderDetail.getRefOrderNo()));

        // 根据关闭的【销售订单号+行号】匹配明细中符合条件的正向履约明细子单，判断正向履约单子单的状态
        List<FulfillmentDetailGetResDTO> fulfillmentDetailGetDTOList = fulfillmentOrderDetailMap.get(orderSDO.getFromSys() + orderSDO.getBusinessType() + orderSDO.getBusinessUnitOutCode() + orderSDO.getOrderBizId());
        log.info("AbstractOrderAtomCloseService#checkFulfillmentOrder fulfillmentOrderDetailResDTOList={}", JSON.toJSONString(fulfillmentDetailGetDTOList));
        if (CollectionUtils.isEmpty(fulfillmentDetailGetDTOList)) {
            return true;
        }

        // 筛选出要关闭的订单行生成的履约单明细
        List<FulfillmentDetailGetResDTO> fulfillmentOrderDetailList = fulfillmentDetailGetDTOList.stream()
                .filter(fo -> orderLineSDO.getSerialNumber().equals(fo.getRefOrderLineNo()))
                .collect(Collectors.toList());
        log.info("AbstractOrderAtomCloseService#checkFulfillmentOrder fulfillmentOrderDetailList={}", JSON.toJSONString(fulfillmentOrderDetailList));
        if(CollectionUtils.isEmpty(fulfillmentOrderDetailList)){
            return true;
        }

        BigDecimal totalShippedQuatity = BigDecimal.ZERO;
        for (FulfillmentDetailGetResDTO fulfillmentOrderDetail : fulfillmentOrderDetailList) {

            if(SetOrderTag.NORMAL.equals(getOrderTag())){
                if (fulfillmentOrderStatusMap.containsKey(fulfillmentOrderDetail.getStatus())) {
                    // 若存在未完成的子单状态（待提交、已提交、待发货、部分发货）当前销售明细行不允许关闭，直接跳过
                    OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
                    orderAtomCloseResponse.setSuccess(false);
                    orderAtomCloseResponse.setSalesOrderNo(fulfillmentOrderDetail.getRefOrderNo());
                    orderAtomCloseResponse.setLineNum(fulfillmentOrderDetail.getRefOrderLineNo());
                    orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-001");
                    orderAtomCloseResponse.setMessage("存在有效的履约单，不允许关闭");
                    closeResponses.add(orderAtomCloseResponse);
                    return false;
                } else if (FulfillmentDetailStatusEnum.COMPLETE.getValue().toString().equals(fulfillmentOrderDetail.getStatus())) {
                    // 查询【已完成】状态正向履约单子单对应的出库数量累加，同【订单数量】比较，如果出库数量累加小于订单数量支持关闭，否则不允许关闭
                    totalShippedQuatity = totalShippedQuatity.add(fulfillmentOrderDetail.getShippedQuantity() == null ? BigDecimal.ZERO : fulfillmentOrderDetail.getShippedQuantity());
                }
            } else if(SetOrderTag.RETURN.equals(getOrderTag())){
                if(fulfillmentReverseOrderStatusMap.containsKey(fulfillmentOrderDetail.getStatus())){
                    // 若存在未完成的子单状态（待提交、已提交、待收货、部分收货）当前销售明细行不允许关闭，直接跳过
                    OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
                    orderAtomCloseResponse.setSuccess(false);
                    orderAtomCloseResponse.setSalesOrderNo(fulfillmentOrderDetail.getRefOrderNo());
                    orderAtomCloseResponse.setLineNum(fulfillmentOrderDetail.getRefOrderLineNo());
                    orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-001");
                    orderAtomCloseResponse.setMessage("存在有效的履约单，不允许关闭");
                    closeResponses.add(orderAtomCloseResponse);
                    return false;
                } else if (FulfillmentDetailStatusEnum.COMPLETE.getValue().toString().equals(fulfillmentOrderDetail.getStatus())) {
                    // 查询【已完成】状态正向履约单子单对应的入库数量累加，同【订单数量】比较，如果入库数量累加小于订单数量支持关闭，否则不允许关闭
                    totalShippedQuatity = totalShippedQuatity.add(fulfillmentOrderDetail.getShippedQuantity() == null ? BigDecimal.ZERO : fulfillmentOrderDetail.getShippedQuantity());
                }
            }
        }

        // 同【订单数量】比较，如果出库数量累加小于订单数量支持关闭，否则不允许关闭
        BigDecimal orderQuantity = new BigDecimal(orderLineSDO.getQuantity());
        if (totalShippedQuatity.compareTo(orderQuantity) >= 0) {
            OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
            orderAtomCloseResponse.setSalesOrderNo(orderLineSDO.getMainOrderBizId());
            orderAtomCloseResponse.setLineNum(orderLineSDO.getSerialNumber());
            orderAtomCloseResponse.setSuccess(false);
            if(SetOrderTag.NORMAL.equals(getOrderTag())){
                orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-004");
                orderAtomCloseResponse.setMessage("履约单子单出库数量等于订单子单数量，不允许关闭");
            } else if(SetOrderTag.RETURN.equals(getOrderTag())){
                orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-007");
                orderAtomCloseResponse.setMessage("履约单子单入库数量等于订单子单数量，不允许关闭");
            }
            closeResponses.add(orderAtomCloseResponse);
            return false;
        }

        return true;
    }

    protected List<FulfillmentDetailGetResDTO> searchFulfillmentOrderList(List<OrderSDO> orderSDOList, List<OrderAtomCloseResponse> closeResponses) {
        List<FulfillmentDetailGetResDTO> fulfillmentDetailDTOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(orderSDOList)) {
            return fulfillmentDetailDTOList;
        }
        OrderSDO orderSDO = orderSDOList.get(0);
        // 分公司订单不校验履约单
//        if (OrderCategoryEnum.COMPANY.getCode().equals(orderSDO.getOrderCategoryCode())) {
//            return fulfillmentDetailDTOList;
//        }

        // 根据关闭的【销售订单号+行号】匹配明细中符合条件的履约明细子单，判断履约单子单的状态
        SearchFulfullmentOrderRequest searchFulfillmentOrderRequest = new SearchFulfullmentOrderRequest();
        searchFulfillmentOrderRequest.setRefOrderNoList(orderSDOList.stream().map(OrderSDO::getOrderBizId).distinct().collect(Collectors.toList()));
        if (NORMAL.equals(orderSDO.getOrderTag())) {
            searchFulfillmentOrderRequest.setFulfillmentDirectionType(FulfillmentDirectionTypeEnum.FORWARD.getValue());
        } else if (RETURN.equals(orderSDO.getOrderTag())) {
            searchFulfillmentOrderRequest.setFulfillmentDirectionType(FulfillmentDirectionTypeEnum.REVERSE.getValue());
        } else {
            OrderAtomCloseResponse orderAtomCloseResponse = new OrderAtomCloseResponse();
            orderAtomCloseResponse.setSalesOrderNo(orderSDO.getOrderBizId());
            orderAtomCloseResponse.setSuccess(false);
            orderAtomCloseResponse.setErrorCode("OC-01-004-01-16-005");
            orderAtomCloseResponse.setMessage("订单类型不正确");
            closeResponses.add(orderAtomCloseResponse);
            return fulfillmentDetailDTOList;
        }
        log.info("AbstractOrderAtomCloseService#searchFulfillmentOrderList searchFulfillmentOrderRequest={}", JSON.toJSONString(searchFulfillmentOrderRequest));
        Result<List<FulfillmentGetResDTO>> result = fulfillmentOrderAbilityAdapter.searchFulfillmentOrder(searchFulfillmentOrderRequest);
        log.info("AbstractOrderAtomCloseService#searchFulfillmentOrderList result={}", JSON.toJSONString(result));
        if (!result.isSuccess() || CollectionUtils.isEmpty(result.getResult())) {
            return fulfillmentDetailDTOList;
        }

        result.getResult().forEach(fulfillmentGetResDTO -> fulfillmentDetailDTOList.addAll(fulfillmentGetResDTO.getDetailList()));
        return fulfillmentDetailDTOList;
    }

    @Override
    public void refuseCallback(SapRefuseCallbackRequest request) {
        // 1.解析回调结果
        // 按外部单号进行分组
        Map<String, List<SalesOrderRefuseRequest>> dataListMap = new HashMap<>();
        for (SalesOrderRefuseRequest data : request.getData()) {
            List<SalesOrderRefuseRequest> dataList;
            if (dataListMap.containsKey(data.getVBELN())) {
                dataList = dataListMap.get(data.getVBELN());
            } else {
                dataList = new ArrayList<>();
            }
            dataList.add(data);
            dataListMap.put(data.getVBELN(), dataList);
        }

        // 发送kafka消息要传的内容
        String fromSys = "";
        String businessUnitCode = "";

        // 2.根据结果修改订单行拒绝状态
        // 发送消息通知来源系统
        List<PushOrderInfoToMnSideRequestOrderInfo> pushOrderInfoList = new ArrayList<>();
        List<OrderSDO> ordersToReleaseOccpuy = new ArrayList<>();
        List<String> salesOrderNos = new ArrayList<>();
        Map<String, List<String>> salesOrderNosMap = Collections.synchronizedMap(new HashMap<>());
        for (String outOrderId : dataListMap.keySet()) {
            OrderSDO order = orderQueryServiceRepository.queryByOuterOrderId(outOrderId);
            log.info("AbstractOrderAtomCloseService#refuseCallback order={}", JSON.toJSONString(order));
            // 校验订单
            if (Objects.isNull(order)) {
                PushOrderInfoToMnSideRequestOrderInfo pushOrderInfo = new PushOrderInfoToMnSideRequestOrderInfo();
                pushOrderInfo.setSalesOrderNo(outOrderId);
                pushOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.FAIL_REFUSED.getOrderStatusCode());
                pushOrderInfo.setMessage(ErrorMessage.code(getOrderTagNameForErrorMsg(), outOrderId).getDisplayErrorMessage());
                pushOrderInfoList.add(pushOrderInfo);
                log.error("AbstractOrderAtomCloseService#refuseCallback checkOrderFail message={}", getOrderTagNameForErrorMsg());
                continue;
            }

            if (StringUtils.isBlank(fromSys)) fromSys = order.getFromSys();
            if (StringUtils.isBlank(businessUnitCode)) businessUnitCode = order.getBusinessUnitOutCode();

            // 按销售订单行号进行分组
            Map<String, SalesOrderRefuseRequest> dataMap = new HashMap<>();
            dataListMap.get(outOrderId).forEach(data -> dataMap.put(data.getPOSNR(), data));
            // 根据关闭结果修改订单行状态
            List<PushOrderInfoToMnSideRequestOrderInfo> pushOrderInfoOrderInfoList = new ArrayList<>();
            List<OrderLineSDO> updateOrderLineList = new ArrayList<>();
            for (OrderLineSDO orderLine : order.getOrderLineSDOS()) {
                SalesOrderRefuseRequest data = dataMap.get(orderLine.getOuterOrderLineId());
                if (ObjectUtils.isEmpty(data)) {
                    // 当前行未进行拒绝操作，直接跳过
                    continue;
                }

                // 构造kafka通知结果
                PushOrderInfoToMnSideRequestOrderInfo pushOrderInfo = new PushOrderInfoToMnSideRequestOrderInfo();
                pushOrderInfo.setSalesOrderNo(order.getOrderBizId());
                pushOrderInfo.setLineNum(orderLine.getSerialNumber());
                pushOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.FAIL_REFUSED.getOrderStatusCode());
                // SAP关闭失败
                if ("E".equals(data.getFLAG())) {
                    pushOrderInfo.setMessage(data.getMESSAGE());
                    pushOrderInfoList.add(pushOrderInfo);
                    // 关闭失败，打印日志后跳过
                    log.error("AbstractOrderAtomCloseService#refuseCallback flagIsE data={}", JSON.toJSONString(data));
                    continue;
                }
                orderLine.setRefuseReasonCode(data.getABGRU());
                log.info("orderLine参数:{}",JSON.toJSONString(orderLine));
                updateOrderLineList.add(orderLine);

                PushOrderInfoToMnSideRequestOrderInfo orderInfo = new PushOrderInfoToMnSideRequestOrderInfo();
                orderInfo.setSalesOrderNo(order.getOrderBizId());
                orderInfo.setLineNum(orderLine.getSerialNumber());
                pushOrderInfoOrderInfoList.add(orderInfo);
            }
            pushOrderInfoList.addAll(pushOrderInfoOrderInfoList);

            // 分公司订单时更新订单状态，集团和直发订单不依赖SAP的回调
            if (OrderCategoryEnum.COMPANY.getCode().equals(order.getOrderCategoryCode())) {
                // 更新订单行状态
                boolean updateOrderLineStatusSuccess = this.updateOrderLineStatus(order, updateOrderLineList);
                for (PushOrderInfoToMnSideRequestOrderInfo pushOrderInfoRequestOrderInfo : pushOrderInfoOrderInfoList) {
                    if (updateOrderLineStatusSuccess) {
                        pushOrderInfoRequestOrderInfo.setMessage("");
                        pushOrderInfoRequestOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.SUCCESS_REFUSED.getOrderStatusCode());
                    } else {
                        pushOrderInfoRequestOrderInfo.setMessage(SalesOrderPushStatusEnum.FAIL_REFUSED.getOrderStatus());
                        pushOrderInfoRequestOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.FAIL_REFUSED.getOrderStatusCode());
                    }
                }

                // 根据所有订单行状态判断是否需要将订单设为已取消
                this.updateOrderStatus(order, order.getOrderLineSDOS());
            }

            // 记录需要释放库存的订单
            ordersToReleaseOccpuy.add(order);

            // 记录关闭成功的销售订单号
            salesOrderNos.add(order.getOrderBizId());

            // 记录关闭成功的销售订单号和行号
            salesOrderNosMap.put(order.getOrderBizId(), pushOrderInfoList.stream().filter(v -> StringUtils.isBlank(v.getMessage())).map(PushOrderInfoToMnSideRequestOrderInfo::getLineNum).collect(Collectors.toList()));
        }
        log.info("AbstractOrderAtomCloseService#refuseCallback pushOrderInfoList={}", JSON.toJSONString(pushOrderInfoList));

        // 3.发送kafka消息通知应用端处理结果
        if (CollectionUtils.isNotEmpty(pushOrderInfoList)) {
            CommonAsyncMessageResponse commonAsyncMessageResponse = new CommonAsyncMessageResponse();
            commonAsyncMessageResponse.setEventCode(AsyncMessageEventEnum.SALES_ORDER_REFUSED.getValue());
            commonAsyncMessageResponse.setEventName(AsyncMessageEventEnum.SALES_ORDER_REFUSED.getLabel());
            commonAsyncMessageResponse.setEventTime(String.valueOf(new Date().getTime()));
            commonAsyncMessageResponse.setFromSys(fromSys);
            commonAsyncMessageResponse.setBusinessUnitCode(businessUnitCode);
            commonAsyncMessageResponse.setData(pushOrderInfoList);
            sendMsgService.sendMsgToSendKafka(commonAsyncMessageResponse);
            log.info("AbstractOrderAtomCloseService#refuseCallback sendMsgToSendKafka message={}", commonAsyncMessageResponse);
        }

        // 4.释放库存预占
        sendMsgService.sendMsgToInventoryRelease(ordersToReleaseOccpuy);

        // 5.发送MQ消息通知其他中心
        sendMsgService.sendSalesOrderChangeMsg(salesOrderNosMap, InnerMessageEventEnum.SALES_ORDER_REFUSED);
    }

    /**
     * 校验订单
     */
    protected String checkOrder(OrderSDO order, String orderNo, OrderAtomCloseResponse response) {
        log.info("AbstractOrderAtomCloseService#checkOrderLine checkOrder:{}; orderNo:{}; response:{}", JSON.toJSONString(order), orderNo, JSON.toJSONString(response));
        String message = ""; // 错误原因

        if (ObjectUtils.isEmpty(order)) {
            message = ErrorMessage.code(getOrderTagNameForErrorMsg(), orderNo).getDisplayErrorMessage();
            response.setMessage(message);
            response.setErrorCode(getOrderTagNameForErrorMsg());
            return message;
        }

        // 已取消、已完成、已推送、待推送状态不允许关闭
        List<Integer> cantCloseStatus = Lists.newArrayList(
                OrderStatus.CANCELLED.getCode(),
                OrderStatus.BEFORE_SUBMIT.getCode(),
                OrderStatus.STAY_PUSH.getCode(),
                OrderStatus.COMPLETED.getCode(),
                OrderStatus.PUSHING.getCode()
        );
        // 校验订单状态
        if (cantCloseStatus.contains(order.getStatus())) {
            message = "当前操作与订单可执行操作不匹配";
            response.setErrorCode("OC-01-001-01-16-053");
            response.setMessage(ErrorMessage.code("OC-01-001-01-16-053").getDisplayErrorMessage());
            return message;
        }

        return message;
    }

    /**
     * 校验订单行
     */
    protected String checkOrderLine(OrderLineSDO orderLine, OrderAtomCloseResponse response) {
        log.info("AbstractOrderAtomCloseService#checkOrderLine orderLine:{}; response:{}", JSON.toJSONString(orderLine), JSON.toJSONString(response));
        String message = ""; // 错误原因

        if (ObjectUtils.isEmpty(orderLine)) {
            message = "订单行不存在";
            response.setMessage(message);
            response.setErrorCode("OC-01-001-01-16-017");
            return message;
        }

        // 已取消、部分交货、已完成、已推送、待推送状态不允许关闭
        List<Integer> cantCloseStatus = Lists.newArrayList(
                OrderStatus.CANCELLED.getCode(),
                OrderStatus.BEFORE_SUBMIT.getCode(),
//                OrderStatus.PARTIAL_DELIVER.getCode(),
                OrderStatus.COMPLETED.getCode(),
                OrderStatus.STAY_PUSH.getCode(),
                OrderStatus.PUSHING.getCode()
        );
        // 校验订单状态
        if (cantCloseStatus.contains(orderLine.getStatus())) {
            message = "当前操作与订单可执行操作不匹配";
            response.setErrorCode("OC-01-001-01-16-053");
            response.setMessage(ErrorMessage.code("OC-01-001-01-16-053").getDisplayErrorMessage());
            return message;
        }

        return message;
    }

    /**
     * 更新订单行状态
     */
    protected boolean updateOrderLineStatus(OrderSDO order, List<OrderLineSDO> orderLineList) {
        for (OrderLineSDO orderLine : orderLineList) {
            if (OrderStatus.PARTIAL_DELIVER.getCode().equals(orderLine.getStatus()) || OrderStatus.PART_RECEIVING.getCode().equals(orderLine.getStatus())) {
                // 部分交货状态的订单行，推进到已完成状态
                orderLine.setStatus(OrderStatus.COMPLETED.getCode());
            } else {
                // 其他状态的订单行，推进到已取消状态
                orderLine.setStatus(OrderStatus.CANCELLED.getCode());
            }
            orderLine.setClosed(GeneralStatusEnum.YES.getCode());
            orderLine.setRefuseReasonName(SalesOrderCloseEnum.descByCode(orderLine.getRefuseReasonCode()));
            orderLine.setModifierId(order.getModifierId());
            orderLine.setModifierName(order.getModifierName());
            orderLine.setGmtModified(new Date());
        }

        Map<String, List<OrderLineSDO>> orderLineMap = orderLineList.stream().collect(Collectors.groupingBy(orderLine -> orderLine.getStatus() + "_" + orderLine.getRefuseReasonCode()));

        try {
            List<Boolean> modifyResultList = new ArrayList<>();
            for (Map.Entry<String, List<OrderLineSDO>> orderLineEntry : orderLineMap.entrySet()) {
                Boolean modifyResult = orderLineWriteRepository.batchModifyStatus(orderLineEntry.getValue());
                modifyResultList.add(modifyResult);
            }
            return modifyResultList.stream().allMatch(result -> result);
        } catch (Exception e) {
            log.error("AbstractOrderAtomCloseService#updateOrderLineStatus modifyOrderLineError error", e);
        }
        return false;
    }

    /**
     * 更新订单状态
     * <p>
     * 更新逻辑：
     * 1. 只要子单包含待提交、待交货、部分交货、待推送的状态之一，主单就为该状态
     * 2. 子单同时存在已完成和已取消的状态，主单就为已完成
     * 3. 子单只存在已取消的状态，主单就为已取消
     */
    protected void updateOrderStatus(OrderSDO order, List<OrderLineSDO> orderLines) {
        log.info("AbstractOrderAtomCloseService#updateOrderStatus before order={}", JSON.toJSONString(order));
        log.info("AbstractOrderAtomCloseService#updateOrderStatus before orderLines={}", JSON.toJSONString(orderLines));
        List<Integer> statusList = Lists.newArrayList(
                OrderStatus.BEFORE_DELIVERY.getCode(),
                OrderStatus.PARTIAL_DELIVER.getCode(),
                OrderStatus.STAY_PUSH.getCode(),
                OrderStatus.WAIT_HANDLE.getCode(),
                OrderStatus.WAIT_RECEIVING.getCode()
        );

        Set<Integer> orderLineStatusSet = new HashSet<>();
        orderLines.forEach(orderLine -> orderLineStatusSet.add(orderLine.getStatus()));
        log.info("AbstractOrderAtomCloseService#updateOrderStatus orderLineStatusSet={}", orderLineStatusSet);

        Integer status = order.getStatus();
        if (orderLineStatusSet.size() == 1) {
            Integer lineStatus = orderLineStatusSet.iterator().next();
            if (lineStatus.equals(OrderStatus.CANCELLED.getCode())) {
                // 1.子单只存在已取消的状态，主单就为已取消
                status = OrderStatus.CANCELLED.getCode();
            } else if (lineStatus.equals(OrderStatus.COMPLETED.getCode())) {
                // 2.子单只存在已完成的状态，主单就为已完成
                status = OrderStatus.COMPLETED.getCode();
            }
        } else if (orderLineStatusSet.size() == 2 && orderLineStatusSet.containsAll(Sets.newHashSet(OrderStatus.CANCELLED.getCode(),  OrderStatus.COMPLETED.getCode()))) {
            // 3.子单只存在已取消和已完成的状态，主单就为已完成
            status = OrderStatus.COMPLETED.getCode();
        } else {
            for (Integer orderLineStatus : orderLineStatusSet) {
                if (OrderStatus.BEFORE_DELIVERY.getCode().equals(orderLineStatus) || OrderStatus.COMPLETED.getCode().equals(orderLineStatus)) {
                    continue;
                }
                // 4.只要子单包含待提交、待交货、部分交货、待推送、待处理、待收货的状态之一，主单就为该状态
                if (statusList.contains(orderLineStatus)) {
                    log.info("AbstractOrderAtomCloseService#updateOrderStatus setStatus({})", orderLineStatus);
                    if (SetOrderTag.EXCHANGE.equals(order.getOrderTag()) && OrderStatus.WAIT_RECEIVING.getCode().equals(orderLineStatus)) {
                        // 换货单还有待收货的退货行时，主单保持待处理状态
                        status = OrderStatus.WAIT_HANDLE.getCode();
                    } else {
                        status = orderLineStatus;
                    }
                    break;
                }
            }
        }
        order.setStatus(status);
        log.info("AbstractOrderAtomCloseService#updateOrderStatus after order={}", JSON.toJSONString(order));
        orderWriteRepository.updateOrder(order);
    }

    protected void paramsCheck(OrderAtomBatchCloseRequest request, String orderCategory) {
        Set<String> orderSet = new HashSet<>();

        List<OrderAtomCloseRequest> requestList = request.getOrderList();
        AssertUtils.isTrue(CollectionUtils.isEmpty(requestList), "OC-01-001-01-15-001", "单据列表");
        AssertUtils.isTrue(requestList.size() > 1000, "OC-01-001-01-15-004", "单据列表", requestList.size(), 1000);
        if (!OrderCategoryEnum.COMPANY.getCode().equals(orderCategory)) {
            // 非分公司请求时，请求限制调整为100
            AssertUtils.isTrue(requestList.size() > 100, "OC-01-001-01-15-004", "单据列表", requestList.size(), 100);
        }
        requestList.forEach(order -> {
            if (StringUtils.isNotBlank(request.getFromSys())) {
                order.setFromSys(request.getFromSys());
            }
            if (StringUtils.isNotBlank(request.getBusinessType())) {
                order.setBusinessType(request.getBusinessType());
            }
            if (StringUtils.isNotBlank(request.getBusinessUnitCode())) {
                order.setBusinessUnitCode(request.getBusinessUnitCode());
            }

            // 入参重复校验
            String orderKey = order.getSalesOrderNo() + "-" + order.getLineNum();
            if (orderSet.contains(orderKey)) {
                throw new FunctionException("OC-01-001-01-15-002", "行号", orderKey);
            }
            orderSet.add(orderKey);

            // 必填校验
            AssertUtils.isTrue(StringUtils.isBlank(order.getFromSys()), "OC-01-001-01-15-001", "来源系统编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getBusinessType()), "OC-01-001-01-15-001", "业态编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getBusinessUnitCode()), "OC-01-001-01-15-001", "业务单元编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getSalesOrderNo()), "OC-01-001-01-15-001", "订单单号");
            AssertUtils.isTrue(StringUtils.isBlank(order.getLineNum()), "OC-01-001-01-15-001", "行号");
            AssertUtils.isTrue(StringUtils.isBlank(order.getCloseCode()), "OC-01-001-01-15-001", "关闭原因编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getModifierCode()), "OC-01-001-01-15-001", "修改人工号");
            AssertUtils.isTrue(StringUtils.isBlank(order.getModifierName()), "OC-01-001-01-15-001", "修改人姓名");

            // 长度校验
            AssertUtils.lengthCheck(order.getFromSys(), 50, true, "OC-01-001-01-15-004", "来源系统编码");
            AssertUtils.lengthCheck(order.getBusinessType(), 10, true, "OC-01-001-01-15-004", "业态编码");
            AssertUtils.lengthCheck(order.getBusinessUnitCode(), 50, true, "OC-01-001-01-15-004", "业务单元编码");
            AssertUtils.lengthCheck(order.getSalesOrderNo(), 50, true, "OC-01-001-01-15-004", "订单单号");
            AssertUtils.lengthCheck(order.getLineNum(), 10, true, "OC-01-001-01-15-004", "行号");
            AssertUtils.lengthCheck(order.getCloseCode(), 50, true, "OC-01-001-01-15-004", "关闭原因编码");
            AssertUtils.lengthCheck(order.getModifierCode(), 50, true, "OC-01-001-01-15-004", "修改人工号");
            AssertUtils.lengthCheck(order.getModifierName(), 50, true, "OC-01-001-01-15-004", "修改人姓名");

            // 枚举校验
            Optional.ofNullable(SalesOrderCloseEnum.of(order.getCloseCode())).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "关闭原因编码"));
        });

        // 字典值校验
        if (!OrderCategoryEnum.COMPANY.getCode().equals(orderCategory)) {
            AssertUtils.isNumber(request.getBusinessType(), true, "OC-01-001-01-15-006", "业态编码");
            dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.FROM_SYS.getCode(), request.getFromSys(), new FunctionException("OC-01-001-01-15-006", "来源系统编码"));
            dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.BUSINESS_TYPE.getCode(), request.getBusinessType(), new FunctionException("OC-01-001-01-15-006", "业态编码"));
            dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.BUSINESS_UNIT_CODE.getCode(), request.getBusinessUnitCode(), new FunctionException("OC-01-001-01-15-006", "业务单元编码"));
        }
    }

    protected List<OrderSDO> querySalesOrder(OrderAtomBatchCloseRequest request) {
        StopWatch stopWatch = new StopWatch("销售订单批量关闭");

        List<OrderAtomCloseRequest> orderList = request.getOrderList();

        // 查询订单信息
        stopWatch.start("queryByOrderBizIds");
        QueryByOrderBizIdsRequest queryByOrderBizIdsRequest = QueryByOrderBizIdsRequest.builder()
                .fromSys(orderList.get(0).getFromSys())
                .businessType(Integer.valueOf(orderList.get(0).getBusinessType()))
                .businessUnitOutCode(request.getBusinessUnitCode())
                .orderBizIds(orderList.stream().map(OrderAtomCloseRequest::getSalesOrderNo).distinct().collect(Collectors.toList()))
                .build();
        List<OrderSDO> orderSDOS = orderQueryServiceRepository.queryByOrderBizIds(queryByOrderBizIdsRequest, true);
        stopWatch.stop();

        // 判断是否包含不存在的单据信息
        List<String> dbSalesOrders = orderSDOS.stream().map(OrderSDO::getOrderBizId).collect(Collectors.toList());
        List<String> noExistSalesOrders = orderList.stream()
                .map(OrderAtomCloseRequest::getSalesOrderNo)
                .filter(salesOrderNo -> !dbSalesOrders.contains(salesOrderNo))
                .distinct()
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(noExistSalesOrders)) {
            throw new FunctionException(getOrderTagNameForErrorMsg(), StringUtils.join(noExistSalesOrders, "、"));
        }

        for (OrderSDO orderSDO : orderSDOS) {
            // 过滤非本接口类型的订单，防止串用
            switch (getOrderTag()) {
                case "exchange":
                    if (!"exchange".equals(orderSDO.getOrderTag())) {
                        throw new FunctionException("OC-03-001-01-15-008", orderSDO.getOrderBizId());
                    }
                    break;
                case "normal":
                    if (!"normal".equals(orderSDO.getOrderTag())) {
                        throw new FunctionException("OC-01-001-01-16-016", orderSDO.getOrderBizId());
                    }
                    break;
                case "return":
                    if (!"return".equals(orderSDO.getOrderTag())) {
                        throw new FunctionException("OC-02-001-01-15-008", orderSDO.getOrderBizId());
                    }
                    break;
            }
        }

        // F-B-b订单把关联订单信息查询出来进行状态校验
        if (OrderCategoryEnum.STOCK.getCode().equals(request.getOrderCategoryCode())) {
            // 查询订单信息
            queryByOrderBizIdsRequest = QueryByOrderBizIdsRequest.builder()
                    .fromSys(request.getFromSys())
                    .businessType(Integer.valueOf(request.getBusinessType()))
                    .businessUnitOutCode(request.getBusinessUnitCode())
                    .orderBizIds(orderSDOS.stream().map(OrderSDO::getRelationNo).distinct().collect(Collectors.toList()))
                    .build();
            List<OrderSDO> relationOrderSDOS = orderQueryServiceRepository.queryByOrderBizIds(queryByOrderBizIdsRequest, true);
            orderSDOS.addAll(relationOrderSDOS);
        }

        log.info("AbstractOrderAtomCloseService#querySalesOrder stopWatch.prettyPrint()={}", stopWatch.prettyPrint());
        return orderSDOS;
    }
}
